package cn.pink.gatesrv;

import cn.pink.common.StatService;
import cn.pink.common.support.tools.cache.CacheTool;
import cn.pink.common.support.tools.cache.ICacheListener;
import cn.pink.common.support.tools.cache.RemoveReason;
import cn.pink.common.support.tools.node.NodeTool;
import cn.pink.core.Node;
import cn.pink.core.NodeInfo;
import cn.pink.core.NodeType;
import cn.pink.core.Port;
import cn.pink.core.config.CacheConfig;
import cn.pink.core.config.IronConfig;
import cn.pink.core.config.NetConfig;
import cn.pink.core.support.Log;
import cn.pink.gatesrv.net.socket.Decoder;
import cn.pink.gatesrv.net.socket.Encoder;
import cn.pink.gatesrv.net.socket.SocketServerHandler;
import cn.pink.gatesrv.net.websocket.WebSocketServerHandler;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.vertx.core.Promise;
import io.vertx.core.net.NetServer;
import io.vertx.core.net.NetServerOptions;
import io.vertx.core.net.impl.NetSocketInternal;
import io.vertx.core.net.impl.VertxHandler;

import java.util.List;

/**
 * @Author: pink
 * @Date: 2022/5/19 11:57
 */
public class GateNode extends Node {
    @Override
    public void start(Promise<Void> startPromise) {
        try {
            port = new Port(String.valueOf(Thread.currentThread().getId()));
            port.startup(this, false);

            port.addService(new GateService(port));

            //启动运行信息统计
            if (IronConfig.STAT_ENABLE) {
                port.addService(new StatService(port));
            }

            NetServerOptions options = new NetServerOptions();
            options.setAcceptBacklog(10240);
            options.setReuseAddress(true);
            options.setTcpNoDelay(true);
            options.setTcpKeepAlive(true);

            NetServer server = vertx.createNetServer(options);

            server.connectHandler(socket -> {
                ChannelPipeline pipeline = ((NetSocketInternal) socket).channelHandlerContext().pipeline();
                pipeline.remove(VertxHandler.class);

                if(IronConfig.COMMON_NET.equals(NetConfig.WEBSOCKET.toString())) {
                    pipeline.addLast(new HttpServerCodec(65536,65536,65536));
                    pipeline.addLast(new HttpObjectAggregator(65536));
                    // WebSocket数据压缩
                    pipeline.addLast(new WebSocketServerCompressionHandler());
                    pipeline.addLast(new WebSocketServerProtocolHandler(IronConfig.GATE_NET_PATH, null, true));
                    pipeline.addLast(new ReadTimeoutHandler(600)); //在READ_TIMEOUT_SECONDS秒内没有收到数据就断掉。
                    pipeline.addLast(new WebSocketServerHandler());
                }
                else if(IronConfig.COMMON_NET.equals(NetConfig.SOCKET.toString())) {
                    pipeline.addLast(new Decoder(), new Encoder(), new SocketServerHandler());
                }
            });

            server.listen(IronConfig.GATE_NET_PORT, res -> {
                if (res.succeeded()) {
                    registerListener();

                    NodeTool.getInstance().registerNode(getId(), port.getId(), NodeType.GATE).onSuccess(v -> super.start(startPromise));
//                Log.gate.info("net server start success, listen port={}", IronConfig.GATE_NET_PORT);
                } else {
                    Log.gate.info("net server start fail, cause={}", res);
                }
            });
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stop() {
        super.stop();
    }

    @Override
    public void registerListener() {
        CacheTool.getInstance().registerListener(CacheConfig.NODE, new ICacheListener() {
            @Override
            public void elementAdd(String key, Object value) {

            }

            @Override
            public void elementUpdate(String key, Object value, Object oldValue) {

            }

            @Override
            public void elementRemove(String key, Object oldValue, RemoveReason reason) {
                onRemoveNode((List<NodeInfo>) oldValue);
            }
        });
    }

    @Override
    public void onRemoveNode(List<NodeInfo> nodeInfos) {

    }
}
